// =((^3^))= EMMCC cpp1
#include "lexer.h"
// =((^3^))= EMMCC cpp1 end

// 【!】展开json.hpp
// 【!】展开DFA.hpp

// =((^3^))= EMMCC cpp2
#include <sstream>
#include <utility>
#include <stdexcept>
#include <cctype>

std::string TokenTypeToString(TokenType type) {
    switch(type) {
// =((^3^))= EMMCC cpp2 end

    // 【!】添加各个TokenType到string的映射

// =((^3^))= EMMCC cpp3
    default: throw std::runtime_error("unknow TokenType!");
    }
    // 不会运行到这里
    return "";
}

Token::Token() { 
    type = TokenType::EMMCC_INVALID; 
    row = 0; 
    col = 0; 
    priority = 0;
}

std::string Token::toString() const {
    return "row:" + std::to_string(row) + " col:" + std::to_string(col)
        + " pri:" + std::to_string(priority)
        + " type:" + TokenTypeToString(type)
        + " val:" + value;
}

LexerError::LexerError() {
    row = 0;
    col = 0;
}

void LexerError::set(const std::string& msg, size_t row_, size_t col_) {
    message = msg;
    row = row_;
    col = col_;
}

std::string LexerError::toString() const {
    return message + " row:" + std::to_string(row) + " col:" + std::to_string(col);
}

class ReaderCaptureInfo {
public:
    ReaderCaptureInfo(size_t idx_=0, size_t row_=0, size_t col_=0) {
        idx = idx_;
        row = row_;
        col = col_;
    }

    size_t idx;
    size_t row;
    size_t col;
};

#define READER_EOF  (0xff)
class Reader {
public:
    static const char eof;
    Reader(const std::string& content):
        m_ss(content) {
        m_ch = '\0';
        m_row = 0;
        m_col = 1;
        m_idx = 0;
        m_line_idx = 0;
        m_line_head_pos = 0;
    }

    /**
     * 尝试读一个字符，没有可读的字符时，ch设为READER_EOF
     */
    void getChar(char& ch) {
        if(m_line_idx < m_line.size()) {
            ch = m_line[m_line_idx ++];
            m_ch = ch;
            m_col ++;
            m_idx ++;
        }
        else {
            m_idx = m_ss.tellg();
            std::getline(m_ss, m_line);
            if(m_ss.eof() == false) {
                m_line.push_back('\n');
            }
            if(m_line.size() > 0) {
                ch = m_line[0];
                m_ch = ch;
                m_row ++;
                m_col = 1;
                m_line_idx = 1;
                m_line_head_pos = m_idx;
                m_idx += 1; // 已经读了一个字符了
            }
            else {
                ch = Reader::eof;
            }
        }
    }

    /**
     * @brief Reader已读入的当前一行的当前位置，是否可以匹配一个字符串
     * @param str 要匹配的字符串
     * @return true 匹配成功返回true，并修改内部状态
     * @return false 否则返回false，内部状态不变
     */
    bool matchString(const std::string& str) {
        if(m_line.substr(m_line_idx, str.size()) == str) {
            m_idx += str.size();
            m_line_idx += str.size();
            m_col += str.size();
            return true;
        }
        return false;
    }

    size_t row() const { return m_row; }
    size_t col() const { return m_col; }
    size_t idx() const { return m_idx; }
    char curChar() const { return m_ch; }

    ReaderCaptureInfo capture() const {
        return {m_idx, m_row, m_col};
    }

    void reset(const ReaderCaptureInfo& info) {
        if(info.idx < m_line_head_pos + m_line.size()) {
            m_line_idx = info.idx - m_line_head_pos;
        }
        else {
            m_ss.seekg(info.idx);
            m_line_idx = 0;
            m_line.clear();
        }
        m_row = info.row;
        m_col = info.col;
        m_idx = info.idx;
    }

private:
    std::string m_line;
    std::stringstream m_ss;
    char m_ch;          // 当前字符
    size_t m_row;       // 当前字符所在行号，从1开始计数
    size_t m_col;       // 当前字符所在列号，从1开始计数
    size_t m_idx;       // reader下一个要读的ch在全文中的下标
    size_t m_line_idx;  // reader下一个要读的ch在当前行中的下标
    size_t m_line_head_pos; // reader当前行的第一个字符在全文中的下标
};

const char Reader::eof = READER_EOF;

/**
 * 匹配器基类
 * 从源文件指定位置起匹配指定的Token
 */
class Matcher {
public:
    Matcher() {}
    virtual ~Matcher() {}

    /**
     * 是否匹配
     * @param reader Reader对象的指针（全局只有一个reader）
     * @param cur_ch [IN_OUT] 当前读取到的字符
     * @param token [OUT] 读取到的token
     * @return 成功返回true，否则返回false
     */
    virtual bool match(Reader* reader, char& cur_ch, Token& token) = 0;
};

class CharMatcher : public Matcher {
public:
    CharMatcher(TokenType type, char ch, size_t priority) {
        m_ch = ch;
        m_type = type;
        m_priority = priority;
    }

    bool match(Reader* reader, char& cur_ch, Token& token) {
        if(cur_ch == m_ch) {
            token.type = m_type;
            token.value = cur_ch;
            token.row = reader->row();
            token.col = reader->col();
            token.priority = m_priority;
            reader->getChar(cur_ch);
            return true;
        }
        return false;
    }

private:
    char m_ch;
    TokenType m_type;
    size_t m_priority;
};

class StringMatcher : public Matcher {
public:
    StringMatcher(TokenType type, const std::string& str, size_t priority):
        m_str(str) {
        m_type = type;
        m_priority = priority;
    }

    bool match(Reader* reader, char& cur_ch, Token& token) {
        (void) cur_ch;
        size_t row = reader->row();
        size_t col = reader->col();
        // 执行这个matcher的时候
        // 说明第一个字符已经匹配上了
        // 跳过第一个字符，匹配剩余部分
        if(reader->matchString(m_str.substr(1))) {
            token.row = row;
            token.col = col;
            token.type = m_type;
            token.value = m_str;
            token.priority = m_priority;
            reader->getChar(cur_ch);
            return true;
        }
        return false;
    }
    
private:
    std::string m_str;
    TokenType m_type;
    size_t m_priority;
};

// class DFACnameMatcher : public Matcher {
// public:
//     DFACnameMatcher();
//     ~DFACnameMatcher();
//     bool match(Reader* reader, char& cur_ch, Token& token) {
//         return false;
//     }
// };

// =((^3^))= EMMCC cpp3 end

// 【!】根据DFACustom的内容生成各个类

// =((^3^))= EMMCC cpp3_1
Lexer::Lexer() {
    // ' '和'~'分别是ascii码中可打印字符的第一个和最后一个
    for(size_t i = 0; i < 128; i++) {
        // 为每个字符创建matcher的vector，不可打印字符的vector空着不用
        m_matcher_map.push_back({});
    }
// =((^3^))= EMMCC cpp3_1 end

    // 【!】遍历所有token
    // 【!】根据token类型创建对应的Match，加入map

// =((^3^))= EMMCC cpp4
}

Lexer::~Lexer() {
    for(Matcher* matcher : m_matchers) {
        delete matcher;
    }
}

// 解析Token结束后的状态信息
class TokenInfo {
public:
    TokenInfo() {next_char = '\0';}
    Token token;
    ReaderCaptureInfo reader_info;
    char next_char;
};

int Lexer::parse(const std::string& content, std::vector<Token>& tokens) {
    Reader reader(content);
    ReaderCaptureInfo reader_info;
    char ch;        // 当前字符
    char head_ch;   // 待解析的token的首字符
    TokenInfo token_info;    // 当前token
    std::vector<TokenInfo> candidate_tokens; // 同一字符开头的token，以及解析后的reader状态

    reader.getChar(ch);
    while(true) {
        if(ch == Reader::eof) {
            break;
        }
        if(m_blank_chars.find(ch) != m_blank_chars.end()) {
            reader.getChar(ch);
            continue;
        }
        reader_info = reader.capture();
        candidate_tokens.clear();
        // 依次尝试匹配每一个matcher
        if(m_matcher_map[ch].empty() == true) {
            m_error.set(std::string("No matcher for char: ") + ch, reader_info.row, reader_info.col);
            return -1;
        }
        head_ch = ch;
        for(Matcher* matcher : m_matcher_map[ch]) {
            reader.reset(reader_info);
            ch = head_ch;
            if(matcher->match(&reader, ch, token_info.token) == true) {
                token_info.reader_info = reader.capture();
                token_info.next_char = ch;
                candidate_tokens.push_back(token_info);
            }
        }
        // 找出一个最长的token
        if(candidate_tokens.empty() == false) {
            size_t longest_idx = 0;
            size_t max_length = candidate_tokens[0].token.value.length();
            size_t cur_length = 0;
            for(size_t i = 1; i < candidate_tokens.size(); i++) {
                cur_length = candidate_tokens[i].token.value.length();
                if(cur_length == max_length) {
                    // 长度相同的情况下，选择优先级高的
                    if(candidate_tokens[i].token.priority == candidate_tokens[longest_idx].token.priority) {
                        m_error.set("tow or more tokens have same length and priority!", reader_info.row, reader_info.col);
                        return -1;
                    }
                    if(candidate_tokens[i].token.priority > candidate_tokens[longest_idx].token.priority) {
                        longest_idx = i;
                        max_length = cur_length;
                    }
                }
                else if(cur_length > max_length) {
                    longest_idx = i;
                    max_length = cur_length;
                }
            }
            tokens.push_back(candidate_tokens[longest_idx].token);
            reader.reset(candidate_tokens[longest_idx].reader_info);
            ch = candidate_tokens[longest_idx].next_char;
        }
        else {
            m_error.set("match failed.", reader_info.row, reader_info.col);
            return -1;
        }
    }
    return 0;
}

LexerError Lexer::getErrorInfo() const {
    return m_error;
}

// =((^3^))= EMMCC cpp4 end
